﻿using ECANPort;
using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using UsingEventAggregator.Core;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using TLDNs.Views;
using HCC = HandyControl.Controls;


namespace TLDNs.ViewModels
{

    /// <summary>
    /// Prism事件绑定
    /// </summary>
    public abstract class EAViewModelBase : BindableBase
    {
        protected IRegionManager regionManager;
        protected IContainerExtension _container;
        protected IEventAggregator _ea;
        public EAViewModelBase(IContainerExtension Container, IRegionManager rm, IEventAggregator ea)
        {
            regionManager = rm;
            _container = Container;
            _ea = ea;
            _ea.GetEvent<ChangeLanguageEvent>().Subscribe(ChangeLanguageEventSub);
            _ea.GetEvent<OpenSFMIsChangeEvent>().Subscribe(SFMFileIsLoadedChangeEventSub);
            UILoadedCommand = new DelegateCommand<ResourceDictionary>(UILoadedCommand_Sub);
        }

        protected static ResourceDictionary LangDic;
        protected void ChangeLanguageEventSub(string language)
        {
            AppResources.Current.Language = language;
            string AsmName = typeof(CanDevViewModelBase).Assembly.GetName().Name;
            Uri langUri = new Uri(@"pack://application:,,,/" + AsmName + ";component/Localization/" + language + ".xaml", UriKind.RelativeOrAbsolute);
            ResourceDictionary newDictionary = new ResourceDictionary();
            newDictionary.Source = langUri;
            if (UIL10N != null)
            {
                UIL10N.MergedDictionaries[0] = newDictionary;
                LangDic = newDictionary;
            }
        }
        public DelegateCommand<ResourceDictionary> UILoadedCommand { get; private set; }
        private ResourceDictionary UIL10N;
        protected virtual void UILoadedCommand_Sub(ResourceDictionary obj)
        {
            UIL10N = obj;
            ChangeLanguageEventSub(Thread.CurrentThread.CurrentCulture.Name);
        }

        protected abstract void SFMFileIsReLoaded();

        protected void SFMFileIsLoadedChangeEventSub()
        {
            var dispatcher = System.Windows.Application.Current.Dispatcher;
            if (dispatcher.CheckAccess())
            {
                SFMFileIsReLoaded();
            }
            else
            {
                dispatcher.BeginInvoke(new Action(() =>
                {
                    SFMFileIsReLoaded();
                }));
            }
        }
    }

    /// <summary>
    /// 带Can驱动的Prism绑定
    /// </summary>
    public abstract class CanDevViewModelBase : EAViewModelBase
    {
        protected static ECAN_Device CanDev;


        public CanDevViewModelBase(IContainerExtension Container, IRegionManager rm, IEventAggregator ea) : base(Container, rm, ea)
        {
            uint[] mCanIndex = new uint[2];
            mCanIndex[0] = 0;
            mCanIndex[1] = 1;
            mCanIndex = MainCanDevViewModelBase.GetIndex_FromDefaultSettings();
            CanDev = ECAN_Device.CreateDevice(mCanIndex);
            _ea.GetEvent<CanStatusChangeEvent>().Subscribe(CanStatusChangeEventSub);

            CAN1SendCommand = new DelegateCommand(CAN1SendCommand_Sub);
            CAN2SendCommand = new DelegateCommand(CAN2SendCommand_Sub);
        }



        public DelegateCommand CAN1SendCommand { get; private set; }
        public DelegateCommand CAN2SendCommand { get; private set; }

        private void CAN1SendCommand_Sub()
        {
            var rt = CanDev.ComPort.Get_HTBByValue(0);
            if (rt.ok)
            {
                CAN_OBJ frameinfo = new CAN_OBJ();
                frameinfo.SendType = 0;
                frameinfo.data = new byte[8];
                frameinfo.Reserved = new byte[3]; // old 2 
                frameinfo.ID = Convert.ToUInt32("11", 16);
                frameinfo.DataLen = Convert.ToByte(8);
                frameinfo.ExternFlag = 0;
                frameinfo.RemoteFlag = 0;
                if (frameinfo.RemoteFlag >= 0)
                {
                    for (int i = 0; i < frameinfo.DataLen; i++)
                    {
                        frameinfo.data[i] = (byte)(i + 11);
                    }
                }
                if (CanDev.SendMsg(ref CanDev.ComPort.HTBs[rt.RefIndex], frameinfo))
                {
                    //_ea.GetEvent<CanWriteCountChangeEvent>().Publish();
                }

            }
            else
            {
                Console.WriteLine((string)LangDic["Can1Failed"]);
            }
        }

        private void CAN2SendCommand_Sub()
        {
            var rt = CanDev.ComPort.Get_HTBByValue(1);
            if (rt.ok)
            {
                CAN_OBJ frameinfo = new CAN_OBJ();
                frameinfo.SendType = 0;
                frameinfo.data = new byte[8];
                frameinfo.Reserved = new byte[3]; // old 2 
                frameinfo.ID = Convert.ToUInt32("22", 16);
                frameinfo.DataLen = Convert.ToByte(8);
                frameinfo.ExternFlag = 0;
                frameinfo.RemoteFlag = 0;
                if (frameinfo.RemoteFlag >= 0)
                {
                    for (int i = 0; i < frameinfo.DataLen; i++)
                    {
                        frameinfo.data[i] = (byte)(i + 21);
                    }
                }

                if (CanDev.SendMsg(ref CanDev.ComPort.HTBs[rt.RefIndex], frameinfo))
                {
                    //_ea.GetEvent<CanWriteCountChangeEvent>().Publish();
                }
            }
            else
            {
                Console.WriteLine((string)LangDic["Can1Failed"]);
            }
        }

        private bool _Can1IsOnline = false;
        private bool _Can2IsOnline = false;
        private bool _CanDevIsOnline = false;

        public bool Can1IsOnline
        {
            get { return _Can1IsOnline; }
            set { SetProperty(ref _Can1IsOnline, value); }
        }
        public bool Can2IsOnline
        {
            get { return _Can2IsOnline; }
            set { SetProperty(ref _Can2IsOnline, value); }
        }
        public bool CanDevIsOnline
        {
            get { return _CanDevIsOnline; }
            set { SetProperty(ref _CanDevIsOnline, value); }
        }

        protected virtual void CanStatusChangeEventSub()
        {
            Can1IsOnline = CanStatusChangeEvent.Can1Online;
            Can2IsOnline = CanStatusChangeEvent.Can2Online;
            if (Can1IsOnline || Can2IsOnline)
                CanDevIsOnline = true;
            else
                CanDevIsOnline = false;
        }

        protected void CanDevWriteData(CAN_OBJ info)
        {
            if (Can1IsOnline)
            {
                var rt = CanDev.ComPort.Get_HTBByValue(0);
                if (rt.ok)
                {

                    if (CanDev.SendMsg(ref CanDev.ComPort.HTBs[rt.RefIndex], info))
                    {
                        //_ea.GetEvent<CanWriteCountChangeEvent>().Publish();
                    }

                }
            }
            if (Can2IsOnline)
            {
                var rt = CanDev.ComPort.Get_HTBByValue(1);
                if (rt.ok)
                {
                    if (CanDev.SendMsg(ref CanDev.ComPort.HTBs[rt.RefIndex], info))
                    {
                        //_ea.GetEvent<CanWriteCountChangeEvent>().Publish();
                    }
                }
            }
        }
    }

    /// <summary>
    /// MainWindowViewModel 专用
    /// </summary>
    public class MainCanDevViewModelBase : CanDevViewModelBase
    {
        public string _Can1ErrMsg = "";
        public string _Can2ErrMsg = "";

        public string Can1ErrMsg
        {
            get { return _Can1ErrMsg; }
            set { SetProperty(ref _Can1ErrMsg, value); }
        }
        public string Can2ErrMsg
        {
            get { return _Can2ErrMsg; }
            set { SetProperty(ref _Can2ErrMsg, value); }
        }

        private static bool _CanDevIsOnlile = false;
        public bool CanDevIsOnlile
        {
            get { return _CanDevIsOnlile; }
            set { SetProperty(ref _CanDevIsOnlile, value); }
        }


        private static bool _OpenCanEnable = true;
        public bool OpenCanEnable
        {
            get { return _OpenCanEnable; }
            set { SetProperty(ref _OpenCanEnable, value); }
        }

        private static INIT_CONFIG _Can1Config;
        public INIT_CONFIG Can1Config
        {
            get { return _Can1Config; }
            set { SetProperty(ref _Can1Config, value); }
        }

        private static INIT_CONFIG _Can2Config;
        public INIT_CONFIG Can2Config
        {
            get { return _Can2Config; }
            set { SetProperty(ref _Can2Config, value); }
        }

        private static bool _Can1Opened = false;
        public bool Can1Opened
        {
            get { return _Can1Opened; }
            set { SetProperty(ref _Can1Opened, value); }
        }
        private static bool _Can2Opened = false;
        public bool Can2Opened
        {
            get { return _Can2Opened; }
            set { SetProperty(ref _Can2Opened, value); }
        }



        public MainCanDevViewModelBase(IContainerExtension Container, IRegionManager rm, IEventAggregator ea) : base(Container, rm, ea)
        {
            ConnectCANCommand = new DelegateCommand(ConnectCANCommand_Sub);
            DisConnectCANCommand = new DelegateCommand(DisConnectCANCommand_Sub);

            CanDev.ECAN_RecvStringDataEvent += CanDev_ECAN_RecvStringDataEvent;
            CanDev.ECAN_ReportStringErrEvent += CanDev_ECAN_ReportStringErrEvent;

            SetCANInitConfigCommand = new DelegateCommand(SetCANInitConfigCommand_Sub);
            _ea.GetEvent<InitCan1ConfigOkEvent>().Subscribe(InitCan1ConfigOkEvent_Sub);
            _ea.GetEvent<InitCan2ConfigOkEvent>().Subscribe(InitCan2ConfigOkEvent_Sub);
            _ea.GetEvent<SetCANInitConfigEvent>().Subscribe(SetCANInitConfigCommand_Sub);

            _ea.GetEvent<ConnectCanEvent>().Subscribe(ConnectCANCommand_Sub);
            _ea.GetEvent<DisConnectCanEvent>().Subscribe(DisConnectCANCommand_Sub);
        }

        private void CanDev_ECAN_ReportStringErrEvent(string mErrInfo, uint CanIndex)
        {
            if (CanIndex == 0)
            {
                Can1ErrMsg = mErrInfo;
            }
            if (CanIndex == 1)
            {
                Can2ErrMsg = mErrInfo;
            }
        }

        private void CanDev_ECAN_RecvStringDataEvent(string info, uint CanIndex)
        {
            if (CanIndex == 0)
            {

            }
            if (CanIndex == 1)
            {

            }
        }

        public DelegateCommand SetCANInitConfigCommand { get; private set; }

        private void SetCANInitConfigCommand_Sub()
        {
            var win = new CANInitConfigWindow("Can1");
            win.Show();
            _ea.GetEvent<InitCan1ConfigEvent>().Publish((Can1Config, Properties.Settings.Default.Can1Enable));
            _ea.GetEvent<InitCan2ConfigEvent>().Publish((Can2Config, Properties.Settings.Default.Can2Enable));
        }

        private void InitCan1ConfigOkEvent_Sub((object obj, bool Enable) tag)
        {
            Can1Config = (INIT_CONFIG)tag.obj;
            Properties.Settings.Default.Can1Enable = tag.Enable;
            Console.WriteLine(Can1Config);
            string tmp;
            if (PubMod.Bin_serializeObjToStr(Can1Config, out tmp))
            {
                Properties.Settings.Default.DefaultCan1Config = tmp;
            }
            Properties.Settings.Default.Save();
        }
        private void InitCan2ConfigOkEvent_Sub((object obj, bool Enable) tag)
        {
            Can2Config = (INIT_CONFIG)tag.obj;
            Properties.Settings.Default.Can2Enable = tag.Enable;
            Console.WriteLine(Can2Config);
            string tmp;
            if (PubMod.Bin_serializeObjToStr(Can2Config, out tmp))
            {
                Properties.Settings.Default.DefaultCan2Config = tmp;
            }
            Properties.Settings.Default.Save();
        }



        public DelegateCommand ConnectCANCommand { get; private set; }
        public DelegateCommand DisConnectCANCommand { get; private set; }


        private void DisConnectCANCommand_Sub()
        {
            SetCanOnlineStatus(false);
            ECANStatus st = CanDev.CloseCAN_Device();
            if (st == ECANStatus.STATUS_ERR)
            {
                HCC.Growl.Error(LangDic["CAN_DeviceCloseErr"].ToString());
            }
            SetCanOnlineStatus(false);
        }

        private void SetCanOnlineStatus(bool Online)
        {
            //OpenCanEnable = !Online;
            CanDevIsOnlile = Online;
            if (CanDev.CanIndex.Contains(0u))
            {
                Can1Opened = Online;
            }
            if (CanDev.CanIndex.Contains(1u))
            {
                Can2Opened = Online;
            }
            CanStatusChangeEvent.Can1Online = Can1Opened;
            CanStatusChangeEvent.Can2Online = Can2Opened;
            _ea.GetEvent<CanStatusChangeEvent>().Publish();
        }

        public static uint[] GetIndex_FromDefaultSettings()
        {
            uint[] mCanIndex = new uint[2];
            if (Properties.Settings.Default.Can1Enable && Properties.Settings.Default.Can2Enable)
            {
                mCanIndex = new uint[2];
                mCanIndex[0] = 0;
                mCanIndex[1] = 1;
            }
            else
            {
                mCanIndex = new uint[1];
                if (Properties.Settings.Default.Can1Enable)
                    mCanIndex[0] = 0;
                if (Properties.Settings.Default.Can2Enable)
                    mCanIndex[0] = 1;
            }
            return mCanIndex;
        }

        private void ConnectCANCommand_Sub()
        {

            INIT_CONFIG[] cfg = new INIT_CONFIG[2];
            cfg[0] = Can1Config;
            cfg[1] = Can2Config;

            uint[] mCanIndex = GetIndex_FromDefaultSettings();
            if (mCanIndex.Length == 1)
            {
                cfg = new INIT_CONFIG[1];
                if (Properties.Settings.Default.Can1Enable)
                {
                    cfg[0] = Can1Config;
                }
                if (Properties.Settings.Default.Can2Enable)
                {
                    cfg[0] = Can2Config;
                }
            }

            CanDevIsOnlile = CanDev.OpenAndStartCAN_Device(cfg, mCanIndex);
            if (CanDevIsOnlile == false)
            {
                HCC.Growl.Info($"{LangDic["ConnectFailed"]}");
            }
            SetCanOnlineStatus(CanDevIsOnlile);

        }

        protected override void SFMFileIsReLoaded()
        {

        }
    }


}
